home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 19 / develop 19 code / Adding GX Printing to QD Apps / Simple Sample GX ƒ / printing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-15  |  16.6 KB  |  630 lines  |  [TEXT/KAHL]

  1. /*********************************************************************
  2.  
  3.     Printing.c
  4.     
  5.     This file contains the printing code for the QuickDraw GX aware
  6.     sample, "Simple Sample GX."
  7.     
  8.     Additional info can be found in the related develop #19 article,
  9.     "Adding QuickDraw GX Printing to QuickDraw Applications."
  10.  
  11.     Dave Hersey, Apple Developer Technical Support.
  12.     
  13.     ——————— Edit Trail ———————
  14.     
  15.     coughed up:                                        1/22/94  - dmh
  16.     cleaned up for 2nd draft of develop article:    3/10/94  - dmh
  17.     cleaned up for final:                            4/14/94  - dmh
  18.     
  19. *********************************************************************/
  20.  
  21. #include "Simple Sample.h"
  22.  
  23.  
  24. /************************************************************
  25.   MyPrintDocument - This routine displays the QuickDraw GX
  26.   or non-QuickDraw GX "Print" dialog, and then prints the
  27.   document.
  28.  
  29. *************************************************************/
  30.  
  31. OSErr MyPrintDocument(MyDocumentPtr whichDocument)
  32. {
  33.     OSErr                err = noErr;
  34.     gxEditMenuRecord    editMenuRec;
  35.     gxDialogResult        result;
  36.  
  37.     if (gGXIsPresent)
  38.     {
  39. /*
  40.     If QuickDraw GX is present, fill in the location of the application's
  41.     Edit menu items, enable/disable appropriate menu items, and display
  42.     the Print dialog.  If the user clicks the Print button, print using
  43.     QuickDraw GX.
  44. */
  45.         editMenuRec.editMenuID    = mEdit;
  46.         editMenuRec.cutItem        = iCut;
  47.         editMenuRec.copyItem    = iCopy;
  48.         editMenuRec.pasteItem    = iPaste;
  49.         editMenuRec.clearItem    = iClear;
  50.         editMenuRec.undoItem    = iUndo;
  51.     
  52.         MyAdjustMenusForPrintDialogs(true);
  53.         result = GXJobPrintDialog(whichDocument->documentJob, &editMenuRec);
  54.         MyAdjustMenusForPrintDialogs(false);
  55.  
  56.         if (result == gxOKSelected)
  57.             err = MyGXPrintLoop(whichDocument);
  58.     }
  59.     else
  60.     {
  61. /*
  62.     If QuickDraw GX is NOT present, open the printer driver, and put up the
  63.     old Print dialog.  If the user clicks the Print button, print using
  64.     the Printing Manager.
  65. */
  66.         PrOpen();
  67.         PrValidate(whichDocument->documentPrintHdl);
  68.         if (PrJobDialog(whichDocument->documentPrintHdl))
  69.             err = MyQDPrintLoop(whichDocument);    // Print using QuickDraw.
  70.         PrClose();
  71.     }
  72.  
  73.     return err;
  74. }
  75.  
  76.  
  77. /************************************************************
  78.   MyPrintOneCopy - This routine sets up job collection items
  79.   so that we'll print one copy of the passed document, then
  80.   it jumps into our printing routine.  This function is only
  81.   called when QuickDraw GX is running.
  82.  
  83. *************************************************************/
  84.  
  85. OSErr MyPrintOneCopy(MyDocumentPtr whichDocument)
  86. {
  87.     OSErr                    err;
  88.     Collection                jobCollection;
  89.     gxCopiesInfo            copiesInfo;
  90.     gxFileDestinationInfo    destInfo;
  91.     gxPageRangeInfo            pageRangeInfo;
  92.     Ptr                        oldCopiesInfo = nil, oldPageRangeInfo = nil, oldDestInfo = nil;
  93.     long                    oldCopiesSize, oldPageRangeInfoSize, oldDestInfoSize;
  94.  
  95. // Get the job collection and set it up to print one copy…
  96.  
  97.     jobCollection = GXGetJobCollection(whichDocument->documentJob);
  98.  
  99. // Set number of copies to 1.
  100.     
  101.     copiesInfo.copies = 1;
  102.     err = MyReplaceCollectionItem(&copiesInfo, sizeof(gxCopiesInfo),
  103.                                     gxCopiesTag, gxPrintingTagID,
  104.                                     jobCollection, &oldCopiesInfo, &oldCopiesSize);
  105.     nrequire(err, ReplaceCopies_error);
  106.  
  107. // Set page range to "all".
  108.  
  109.     pageRangeInfo.simpleRange.optionChosen = gxDefaultPageRange;
  110.     pageRangeInfo.minFromPage = 1;
  111.     pageRangeInfo.simpleRange.fromPage = 1;
  112.     pageRangeInfo.maxToPage = whichDocument->numPages;
  113.     pageRangeInfo.simpleRange.toPage = whichDocument->numPages;
  114.     pageRangeInfo.simpleRange.printAll = true;
  115.     err = MyReplaceCollectionItem(&pageRangeInfo, sizeof(gxPageRangeInfo),
  116.                                     gxPageRangeTag, gxPrintingTagID,
  117.                                     jobCollection, &oldPageRangeInfo, &oldPageRangeInfoSize);
  118.     nrequire(err, ReplacePageRange_error);
  119.  
  120. // Set destination to "printer".
  121.  
  122.     destInfo.toFile = false;
  123.     err = MyReplaceCollectionItem(&destInfo, sizeof(gxFileDestinationInfo),
  124.                                   gxFileDestinationTag, gxPrintingTagID,
  125.                                   jobCollection, &oldDestInfo, &oldDestInfoSize);
  126.     nrequire(err, ReplaceDestination_error);
  127.  
  128. // Print one copy of our document.
  129.  
  130.     err = MyGXPrintLoop(whichDocument);
  131.  
  132. /*
  133.     Restore original number of copies, page range, and output
  134.     destination in case anybody uses that info.
  135. */
  136.  
  137. ReplaceDestination_error:
  138.     MyReplaceCollectionItem(oldDestInfo, oldDestInfoSize,
  139.                             gxFileDestinationTag, gxPrintingTagID,
  140.                             jobCollection, nil, nil);
  141. ReplacePageRange_error:
  142.     MyReplaceCollectionItem(oldPageRangeInfo, oldPageRangeInfoSize,
  143.                             gxPageRangeTag, gxPrintingTagID,
  144.                             jobCollection, nil, nil);
  145. ReplaceCopies_error:
  146.     MyReplaceCollectionItem(oldCopiesInfo, oldCopiesSize,
  147.                               gxCopiesTag, gxPrintingTagID,
  148.                             jobCollection, nil, nil);
  149.  
  150. // Dispose of the pointers that MyReplaceCollectionItem created.
  151.  
  152.     if (oldCopiesInfo)
  153.         DisposePtr(oldCopiesInfo);
  154.  
  155.     if (oldPageRangeInfo)
  156.         DisposePtr(oldPageRangeInfo);
  157.  
  158.     if (oldDestInfo)
  159.         DisposePtr(oldDestInfo);
  160.  
  161.     return err;
  162. }
  163.  
  164.  
  165. /************************************************************
  166.   MyQDPrintLoop - This is our non-QuickDraw GX printing
  167.   routine.
  168.  
  169. *************************************************************/
  170.  
  171. OSErr MyQDPrintLoop(MyDocumentPtr whichDocument)
  172. {
  173.     OSErr            err = noErr;
  174.     THPrint            hPrint;
  175.     TPPrPort        printPort;
  176.     TPrStatus        theStatus;
  177.     short            copy, pg, iFstPage, iLstPage, oldCurPage;
  178.  
  179.     hPrint = whichDocument->documentPrintHdl;
  180.     oldCurPage = whichDocument->curPage;
  181.  
  182.     iFstPage = (*hPrint)->prJob.iFstPage;
  183.     if (iFstPage < 1)
  184.         iFstPage = 1;
  185.  
  186.     iLstPage = (*hPrint)->prJob.iLstPage;
  187.     if (iLstPage > whichDocument->numPages)
  188.         iLstPage = whichDocument->numPages;
  189.  
  190.     (*hPrint)->prJob.iFstPage = 1;
  191.     (*hPrint)->prJob.iLstPage = 9999;
  192.  
  193. /*
  194.     Loop for the number of copies we need to make, opening a
  195.     document and a page for each.
  196. */
  197.     for (copy = 1; !err && (copy <= (*hPrint)->prJob.iCopies); copy++)
  198.     {
  199.         printPort = PrOpenDoc(hPrint, nil, nil);
  200.  
  201.         if (!(err = PrError()))
  202.             for (pg = iFstPage; pg <= iLstPage; pg++)
  203.             {
  204.                 PrOpenPage(printPort, nil);
  205.  
  206.                 whichDocument->curPage = pg;
  207.                 MyDrawContents(whichDocument->documentWindow);
  208.         
  209.                 PrClosePage(printPort);
  210.             }
  211.  
  212.         PrCloseDoc(printPort);
  213.     }
  214.  
  215. // When finished printing, call PrPicFile (if necessary).
  216.  
  217.     if (!err) err = PrError();
  218.  
  219.     if (!err && ((*hPrint)->prJob.bJDocLoop == bSpoolLoop))
  220.         PrPicFile(hPrint, nil, nil, nil, &theStatus);
  221.     
  222.     whichDocument->curPage = oldCurPage;
  223.  
  224.     return err;
  225. }
  226.  
  227.  
  228. /************************************************************
  229.   MyGXPrintLoop - This is our QuickDraw GX printing
  230.   routine.
  231.  
  232. *************************************************************/
  233.  
  234. OSErr MyGXPrintLoop(MyDocumentPtr whichDocument)
  235. {
  236.     OSErr                err;
  237.     long                firstPage, lastPage, numPages, pg;
  238.     long                oldPage;
  239.     gxViewPort            printViewPort;
  240.     Point                patStretch = {1,1};
  241.     gxFormat            pageFormat;
  242.     Rect                everywhereRect;
  243.     gxShape                pageShape;
  244.     MySpoolDataRec        spoolData;
  245.  
  246.     oldPage = whichDocument->curPage;
  247.  
  248. /*
  249.     Determine which pages the user selected to print.  If
  250.     the user specifies a page range that is greater than
  251.     the actual number of pages in the document, only print
  252.     those pages that are actually in the document. 
  253. */
  254.     GXGetJobPageRange(whichDocument->documentJob, &firstPage, &lastPage);
  255.     
  256.     if (lastPage > whichDocument->numPages)
  257.         lastPage = whichDocument->numPages;
  258.  
  259. /*
  260.     Calculate the total number of pages to print, and begin
  261.     printing if there are no errors.
  262. */
  263.     numPages = lastPage - firstPage +1;
  264.     err = GXGetJobError(whichDocument->documentJob);
  265.     nrequire(err, PageRangeError);
  266.  
  267.     GXStartJob(whichDocument->documentJob, whichDocument->documentTitle, numPages);
  268.     err = GXGetJobError(whichDocument->documentJob);
  269.     nrequire(err, StartJobFailed);
  270.  
  271. /*
  272.     Create a new viewport for printing, and set our translator rects
  273.     to "wide open" so they include all data we're drawing.  For each
  274.     page we print, call GXStartPage, draw, and call GXFinishPage.
  275. */
  276.     SetRect(&everywhereRect, 0, 0, 32767, 32767);
  277.     printViewPort = GXNewViewPort(gxScreenViewDevices);
  278.  
  279.     for (pg = firstPage; (err == noErr) && (pg <= lastPage); pg++)
  280.     {
  281.  
  282. // Get the page's format and start printing the page.
  283.  
  284.         pageFormat = whichDocument->pageFormat[pg -1];
  285.  
  286.         if (pageFormat == nil)
  287.             pageFormat = GXGetJobFormat(whichDocument->documentJob, 1);
  288.  
  289.         GXStartPage(whichDocument->documentJob,
  290.                     pg,
  291.                     pageFormat,
  292.                     1,
  293.                     &printViewPort);                                
  294.  
  295.         err = GXGetJobError(whichDocument->documentJob);
  296.  
  297. /*
  298.     If there were no errors, set up the Translator, draw the QuickDraw
  299.     data for the current page and remove the Translator.
  300.     
  301.     Note that, although it looks like it takes a GrafPtr,
  302.     GXInstallQDTranslator actually requires a pointer to a CGrafPort,
  303.     and will crash if you pass it a true GrafPtr.
  304. */
  305.         nrequire(err, StartPageFailed);
  306.         spoolData.printViewPort = printViewPort;
  307.         GXGetFormatDimensions(pageFormat, &spoolData.pageArea, nil);
  308.  
  309.         GXInstallQDTranslator(whichDocument->documentWindow,
  310.                               gxDefaultOptionsTranslation,
  311.                               &everywhereRect, &everywhereRect,
  312.                               patStretch, MyPrintAShape,
  313.                               &spoolData);
  314.  
  315.         whichDocument->curPage = pg;
  316.         SetPort(whichDocument->documentWindow);
  317.         MyDrawContents(whichDocument->documentWindow);    
  318.         GXRemoveQDTranslator(whichDocument->documentWindow, nil);
  319.  
  320. // Finish the page.
  321.  
  322.         GXFinishPage(whichDocument->documentJob);
  323.     }
  324.  
  325. // Finish printing.
  326.  
  327. StartPageFailed:
  328.  
  329.     GXFinishJob(whichDocument->documentJob);
  330.     err = GXGetJobError(whichDocument->documentJob);
  331.         
  332.     GXDisposeViewPort(printViewPort);
  333.     whichDocument->curPage = oldPage;
  334.  
  335. StartJobFailed:
  336. PageRangeError:
  337.     return err;
  338. }
  339.  
  340.  
  341. /************************************************************
  342.   MyPrintAShape - This is a spool proc. for the translator
  343.   routines. In this routine, we simply draw each shape
  344.   we're passed (printing it).  You could also capture each
  345.   shape into one gxPicture shape, and then do one draw of
  346.   that afterwards.
  347.  
  348. *************************************************************/
  349.  
  350. OSErr MyPrintAShape(gxShape currentShape, long refCon)
  351. {
  352.     MySpoolDataPtr        spoolData;
  353.     gxShapeType            theShapeType;
  354.  
  355. /*
  356.     Don't waste time spooling the shape if it's being
  357.     drawn completely off the page.
  358. */
  359.     spoolData = (MySpoolDataPtr) refCon;
  360.     theShapeType = GXGetShapeType(currentShape);
  361.     
  362.     if ((theShapeType == gxEmptyType)   || 
  363.         (theShapeType == gxFullType)    || 
  364.         (theShapeType == gxPictureType) ||
  365.         (GXTouchesBoundsShape(&spoolData->pageArea, currentShape)))
  366.     {
  367.         GXSetShapeViewPorts(currentShape, 1, &spoolData->printViewPort);
  368.         GXDrawShape(currentShape);
  369.     }
  370.     
  371.     return (OSErr) GXGetGraphicsError(nil);
  372. }
  373.  
  374.  
  375. /************************************************************
  376.   MyDoPageSetup - This routine handles the "Page Setup"
  377.   dialog for QuickDraw GX and non-QuickDraw GX environments.
  378.  
  379. *************************************************************/
  380.  
  381. Boolean MyDoPageSetup(MyDocumentPtr whichDocument)
  382. {
  383.     Boolean                result;
  384.     gxDialogResult        dlgResult;
  385.     gxEditMenuRecord    editMenuRec;
  386.  
  387.     if (gGXIsPresent)                        // QuickDraw GX is being used.
  388.     {
  389. /*
  390.     Fill in the location of the application’s Edit menu items
  391.     and enable the appropriate menu items. 
  392. */
  393.         editMenuRec.editMenuID    = mEdit;
  394.         editMenuRec.cutItem        = iCut;
  395.         editMenuRec.copyItem    = iCopy;
  396.         editMenuRec.pasteItem    = iPaste;
  397.         editMenuRec.clearItem    = iClear;
  398.         editMenuRec.undoItem    = iUndo;
  399.  
  400.         MyAdjustMenusForPrintDialogs(true);
  401.         dlgResult = GXJobDefaultFormatDialog(whichDocument->documentJob, &editMenuRec);
  402.         MyAdjustMenusForPrintDialogs(false);
  403.         result = (dlgResult == gxOKSelected);
  404.     }
  405.     else                                    // QuickDraw GX is not being used.
  406.     {
  407.         PrOpen();
  408.         PrValidate(whichDocument->documentPrintHdl);
  409.         result = PrStlDialog(whichDocument->documentPrintHdl);
  410.         PrClose();
  411.     }
  412.  
  413.     return result;
  414. }
  415.  
  416.  
  417. /************************************************************
  418.   MyDoCustomPageSetup - This routine handles the "Custom
  419.   Page Setup" dialog for QuickDraw GX and is never called
  420.   unless QuickDraw GX is being used.
  421.  
  422. *************************************************************/
  423.  
  424. Boolean MyDoCustomPageSetup(MyDocumentPtr whichDocument)
  425. {
  426.     OSErr                    err = noErr;
  427.     gxDialogResult            result;
  428.     gxEditMenuRecord        editMenuRec;
  429.     gxFormat                pageFormat;
  430.     Boolean                    newPgFormat = false;
  431.  
  432. /*
  433.     Fill in the location of the application’s Edit menu items
  434.     and enable the appropriate menu items. 
  435. */
  436.     editMenuRec.editMenuID    = mEdit;
  437.     editMenuRec.cutItem        = iCut;
  438.     editMenuRec.copyItem    = iCopy;
  439.     editMenuRec.pasteItem    = iPaste;
  440.     editMenuRec.clearItem    = iClear;
  441.     editMenuRec.undoItem    = iUndo;
  442.  
  443.     MyAdjustMenusForPrintDialogs(true);
  444.     
  445. /*
  446.     If we have an existing page format, we'll modify that.
  447.     Otherwise, we'll need to create a new format and use that.
  448. */
  449.     if (whichDocument->pageFormat[whichDocument->curPage -1] != nil)
  450.         pageFormat = whichDocument->pageFormat[whichDocument->curPage -1];
  451.     else
  452.     {
  453.         pageFormat = GXNewFormat(whichDocument->documentJob);
  454.         newPgFormat = true;
  455.         err = GXGetJobError(whichDocument->documentJob);
  456.     }
  457.  
  458. // If no errors, display the format dialog.
  459.  
  460.     if (err == noErr)
  461.     {
  462.         result = GXFormatDialog(pageFormat, &editMenuRec, nil);
  463.  
  464.         switch (result)
  465.         {
  466.  
  467. /*
  468.     If the user selected "Remove", use the default job format
  469.     with this page.  For our application, we indicate this by
  470.     storing nil for the format reference in our structure.
  471.     
  472.     If "OK" was selected, store the new format with this page.
  473. */
  474.             case gxRevertSelected:
  475.                 GXDisposeFormat(pageFormat);
  476.                 pageFormat = nil;
  477.  
  478.             case gxOKSelected:
  479.                 whichDocument->pageFormat[whichDocument->curPage -1] = pageFormat;
  480.                 break;
  481.  
  482. /*
  483.     If the user selected "Cancel", dispose of our cloned copy
  484.     of the default job format, if we made one.
  485. */
  486.             case gxCancelSelected:
  487.                 if (newPgFormat) GXDisposeFormat(pageFormat);
  488.                 break;
  489.         }
  490.     }
  491.  
  492.     MyAdjustMenusForPrintDialogs(false);
  493.  
  494.     return newPgFormat;
  495. }
  496.  
  497.  
  498. /************************************************************
  499.   MyRepaginateDoc - This routine handles repagination of our
  500.   document.
  501.  
  502. *************************************************************/
  503.  
  504. void MyRepaginateDoc(MyDocumentPtr whichDocument)
  505. {
  506.     long            pageNum;
  507.     Rect            repaginateRect;
  508.     gxRectangle        pageArea, paperArea;
  509.     gxFormat        pageFormat;
  510.  
  511.     for (pageNum = 1; pageNum <= whichDocument->numPages; pageNum++)
  512.     {
  513.  
  514. /*
  515.     Repaginate our document using the format's page area
  516.     if QuickDraw GX is being used, or else the print
  517.     record's rPage.
  518. */
  519.         if (gGXIsPresent)                    // QuickDraw GX is being used.
  520.         {
  521.             pageFormat = whichDocument->pageFormat[pageNum -1];
  522.  
  523.             if (pageFormat == nil)
  524.                 pageFormat = GXGetJobFormat(whichDocument->documentJob, 1);
  525.             
  526.             GXGetFormatDimensions(pageFormat, &pageArea, &paperArea);
  527.  
  528.             SetRect(&repaginateRect,
  529.                     pageArea.left >>16,
  530.                     pageArea.top >>16,
  531.                     pageArea.right >>16,
  532.                     pageArea.bottom >>16);
  533.         }
  534.         else                                // QuickDraw GX isn't being used.
  535.             repaginateRect = (*whichDocument->documentPrintHdl)->prInfo.rPage;
  536.  
  537.     /*
  538.         Repaginate the document based on our printable area.
  539.         .
  540.         .
  541.         .
  542.     */
  543.  
  544.     }
  545. }
  546.  
  547.  
  548. /************************************************************
  549.   MyReplaceCollectionItem - This routine replaces a
  550.   collection item with the passed data.  If the oldData
  551.   pointer is not nil, the data that's being replaced is
  552.   returned in it.  (If the item doesn't already exist, then
  553.   a copy of the newData is returned instead.)  Note that the
  554.   oldData pointer is actually created in this routine.  You
  555.   just pass a pointer indicating where to store it (or nil
  556.   if you don't want the old data returned).
  557.  
  558. *************************************************************/
  559.  
  560. OSErr MyReplaceCollectionItem(void *newData, long collectSize,
  561.                               OSType collectType, long collectID,
  562.                               Collection whichCollection,
  563.                               Ptr *oldData, long *oldDataSize)
  564. {
  565.     OSErr    err;
  566.     long    index;
  567.  
  568. /*
  569.     If we're supposed to return the old data, get it.
  570.     If there is no old data, return a copy of the new data.
  571. */
  572.     if (oldData)
  573.     {
  574.         err = GetCollectionItemInfo(whichCollection,
  575.                                     collectType,
  576.                                     collectID,
  577.                                     dontWantIndex,
  578.                                     oldDataSize,
  579.                                     dontWantAttributes);
  580.         if (err)
  581.         {
  582.             *oldDataSize = collectSize;
  583.             *oldData = NewPtrSys(*oldDataSize);
  584.             if (!(err = MemError()))
  585.                 BlockMove(newData, *oldData, collectSize);
  586.         }
  587.         else
  588.         {
  589.             *oldData = NewPtrSys(*oldDataSize);
  590.             if (!(err = MemError()))
  591.                 err = GetCollectionItem(whichCollection,
  592.                                         collectType,
  593.                                         collectID,
  594.                                         dontWantSize,
  595.                                         *oldData);
  596.         }
  597.  
  598.         nrequire(err, CouldNotSetOldData);
  599.     }
  600.  
  601. /*
  602.     If we're adding a new collection item, do so.  Otherwise,
  603.     get the existing item's index and replace the old collection
  604.     item.
  605. */
  606.     err = AddCollectionItem(whichCollection,
  607.                             collectType,
  608.                             collectID,
  609.                             collectSize,
  610.                             newData);
  611.  
  612.     if (err == collectionItemLockedErr)
  613.     {
  614.         err = GetCollectionItemInfo(whichCollection,
  615.                                     collectType,
  616.                                     collectID,
  617.                                     &index,
  618.                                     dontWantSize,
  619.                                     dontWantAttributes);
  620.         if (!err)
  621.             err = ReplaceIndexedCollectionItem(whichCollection,
  622.                                                index,
  623.                                                collectSize,
  624.                                                newData);
  625.     }
  626.  
  627. CouldNotSetOldData:
  628.     return err;
  629. }
  630.